package request.monitor;

import java.net.Socket;
import java.net.ServerSocket;
import java.net.SocketTimeoutException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.PrintWriter;

import soar.basic.*;

import request.share.*;

abstract class Command
{/*{{{*/
    String name;
    String ab;
    String desc;
    String usage;

    public abstract String call(String request);
}/*}}}*/

class CommandShutdown extends Command
{
    CommandShutdown()
    {/*{{{*/
        this.name="shutdown";
        this.ab="shutdown";
        this.desc="shutdown server";
        this.usage="shutdown";
    }/*}}}*/

    public String call(String request)
    {/*{{{*/
        Cnfg cnfg=Cnfg.getInstance();
        Operate operate=Operate.getInstance();
        operate.shutdown();

        try { Thread.sleep(1*1000); } catch(Exception e) {};

        String response;
        final int TRY_NUM=10;
        int i;
        for(i=0; i<TRY_NUM; ++i)
        {
            int worker_idx;
            for(worker_idx=0; worker_idx<cnfg.workers; ++worker_idx)
            {
                if(operate.isWorkerRunning(worker_idx))
                {
                    break;
                }
            }
            if(worker_idx == cnfg.workers)
            {
                break;
            }
            try { Thread.sleep(1*1000); } catch(Exception e) {};
        }
        if(i == TRY_NUM)
        {
            response="Shutdown not complete, try again";
        }
        else
        {
            response="Shutdown complete, quitting...";
        }

        return response;
    }/*}}}*/
}

class CommandPrintClient extends Command
{
    CommandPrintClient()
    {/*{{{*/
        this.name="printclient";
        this.ab="pclt";
        this.desc="print client ip & port";
        this.usage="printclient(pclt)";
    }/*}}}*/

    public String call(String request)
    {/*{{{*/
        return Stat.getInstance().showClients();
    }/*}}}*/
}

class CommandPrintService extends Command
{
    CommandPrintService()
    {/*{{{*/
        this.name="printservice";
        this.ab="psvc";
        this.desc="print service status";
        this.usage="printservice(psvc)";
    }/*}}}*/

    public String call(String request)
    {/*{{{*/
        return Stat.getInstance().showSvcs();
    }/*}}}*/
}

public class Monitor
{
    private String __CLASS__=Monitor.class.getName();

    private ServerSocket server;

    public Monitor(ServerSocket server)
    {/*{{{*/
        this.server=server;
    }/*}}}*/

    private Command[] commands=
    {
        new CommandShutdown(),
        new CommandPrintClient(),
        new CommandPrintService(),
    };

    private String callcmd(String request)
    {/*{{{*/
        request=request.trim();
        if(request.isEmpty())
        {
            return "command invalid\n";
        }

        int idx=request.indexOf(" ");
        String cmd;
        String body;
        if(idx == -1)
        {
            cmd=request;
            body="";
        }
        else
        {
            cmd=request.substring(0, idx);
            body=request.substring(idx).trim();
        }
        //Errlog.add(__CLASS__+": cmd:"+cmd+" body:"+body);

        cmd=cmd.toLowerCase();
        if(cmd.equals("help") || cmd.equals("h"))
        {
            if(!body.isEmpty())
            {
                for(Command command : this.commands)
                {
                    if(command.name.equals(body) ||
                            command.ab.equals(body))
                    {
                        return "Description: "+command.desc+"\n"+
                            "Usage: "+command.usage+"\n";
                    }
                }
            }
            String response=
                "help [command]\n"+
                "commands:\n";
            for(Command command : this.commands)
            {
                response=response+"    "+command.name+"\n";
            }
            return response;
        }
        else
        {
            for(Command command : this.commands)
            {
                if(command.name.equals(cmd) || command.ab.equals(cmd))
                {
                    String response=command.call(body);
                    return response;
                }
            }
            return "command("+cmd+") not found";
        }
    }/*}}}*/

    public void start()
    {/*{{{*/
        Operate operate=Operate.getInstance();

        while(!operate.isShutdown())
        {
            Socket console=null;
            BufferedReader in=null;
            PrintWriter out=null;
            try
            {
                console=this.server.accept();
                console.setSoTimeout(5*60*1000);
                in=new BufferedReader(new InputStreamReader(
                            console.getInputStream()));
                out=new PrintWriter(console.getOutputStream(), true);
                Errlog.add(__CLASS__+": new console");
            }
            catch(Exception e)
            {
                continue;
            }

            while(!operate.isShutdown())
            {
                try
                {
                    String request=in.readLine();
                    if(request == null)
                    {
                        Errlog.add(__CLASS__+": console disconnect");
                        break;
                    }
                    String response=callcmd(request);
                    out.println(response);
                }
                catch(SocketTimeoutException e)
                {
                    Errlog.add(__CLASS__+": console timeout, "+
                            e.toString());
                    break;
                }
                catch(Exception e)
                {
                    Errlog.add(__CLASS__+": unknown: "+ e.toString());
                    break;
                }
            }

            try
            {
                console.close();
            }
            catch(Exception e)
            {
            }
        }
    }/*}}}*/
}
